package com;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.Security;

public final class SslContextFactory {

    private static String CLIENT_KEY_STORE = "G:\\ssl\\client\\keys";
    private static String CLIENT_TRUST_KEY_STORE = "G:\\ssl\\client\\trust";
    private static String CLIENT_KEY_STORE_PASSWORD = "123456";
    private static String CLIENT_TRUST_KEY_STORE_PASSWORD = "123456";


    private static String SERVER_KEY_STORE = "G:\\ssl\\server\\keys";
    private static String SERVER_TRUST_KEY_STORE = "G:\\ssl\\server\\trust";
    private static String SERVER_KEY_STORE_PASSWORD = "123456";
    private static String SERVER_TRUST_KEY_STORE_PASSWORD = "123456";


    private static final String PROTOCOL = "TLS";
    private static final SSLContext SERVER_CONTEXT;
    private static final SSLContext CLIENT_CONTEXT;

    public SslContextFactory(String type, String key_store, String key_store_password, String trust_key_store, String trust_key_password) {
        if ("server".equals(type)) {
            SERVER_KEY_STORE = key_store;
            SERVER_KEY_STORE_PASSWORD = key_store_password;
            SERVER_TRUST_KEY_STORE = trust_key_store;
            SERVER_TRUST_KEY_STORE_PASSWORD = trust_key_password;
        } else if ("client".equals(type)) {
            CLIENT_KEY_STORE = key_store;
            CLIENT_KEY_STORE_PASSWORD = key_store_password;
            CLIENT_TRUST_KEY_STORE = trust_key_store;
            CLIENT_TRUST_KEY_STORE_PASSWORD = trust_key_password;
        }
    }

    static {
        String algorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm");
        if (algorithm == null) {
            algorithm = "SunX509";
        }

        SSLContext serverContext;
        SSLContext clientContext;
        try {

            //加载证书库
            KeyStore ks = KeyStore.getInstance("JKS");
            ks.load(new FileInputStream(SERVER_KEY_STORE), SERVER_KEY_STORE_PASSWORD.toCharArray());

            //加载信任库
            KeyStore trustKs = KeyStore.getInstance("JKS");
            trustKs.load(new FileInputStream(SERVER_TRUST_KEY_STORE), SERVER_TRUST_KEY_STORE_PASSWORD.toCharArray());

            //创建并初始化证书库工厂
            String alg = KeyManagerFactory.getDefaultAlgorithm();
//        KeyManagerFactory kf = KeyManagerFactory.getInstance("SunX509");
            KeyManagerFactory kmf = KeyManagerFactory.getInstance(alg);
            kmf.init(ks, SERVER_KEY_STORE_PASSWORD.toCharArray());

            // 创建并初始化信任库工厂
            String alg_trust = TrustManagerFactory.getDefaultAlgorithm();
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(alg_trust);
            tmf.init(trustKs);

            // Initialize the SSLContext to work with our key managers.
            serverContext = SSLContext.getInstance(PROTOCOL);

//            init(KeyManager[],TrustManager[],SecureRandom);

            serverContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
        } catch (Exception e) {
            throw new Error("Failed to initialize the server-side SSLContext", e);
        }

        try {
            KeyStore ks = KeyStore.getInstance("JKS");
            ks.load(new FileInputStream(CLIENT_KEY_STORE), CLIENT_KEY_STORE_PASSWORD.toCharArray());
            //加载信任库
            KeyStore trustKs = KeyStore.getInstance("JKS");
            trustKs.load(new FileInputStream(CLIENT_TRUST_KEY_STORE), CLIENT_TRUST_KEY_STORE_PASSWORD.toCharArray());

            //创建并初始化证书库工厂
            String alg = KeyManagerFactory.getDefaultAlgorithm();
//        KeyManagerFactory kf = KeyManagerFactory.getInstance("SunX509");
            KeyManagerFactory kmf = KeyManagerFactory.getInstance(alg);
            kmf.init(ks, CLIENT_KEY_STORE_PASSWORD.toCharArray());

            // 创建并初始化信任库工厂
            String alg_trust = TrustManagerFactory.getDefaultAlgorithm();
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(alg_trust);
            tmf.init(trustKs);
            /**
             * TLS安全套接字
             * Returns a SSLContext object that implements the specified secure socket protocol.
             */
            clientContext = SSLContext.getInstance(PROTOCOL);
            clientContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
        } catch (Exception e) {
            throw new Error("Failed to initialize the client-side SSLContext", e);
        }

        SERVER_CONTEXT = serverContext;
        CLIENT_CONTEXT = clientContext;
    }

    public static SSLContext getServerContext() {
        return SERVER_CONTEXT;
    }

    public static SSLContext getClientContext() {
        return CLIENT_CONTEXT;
    }

    private SslContextFactory() {
        // Unused
    }
}